﻿using OpenCvSharp;
using OpenCvSharp.Extensions;
using OpenCvSharp.ImgHash;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FileToVideo.Helpers
{
    /// <summary>
    /// 图片比较工具
    /// </summary>
    public class ImageDiffUtils
    {
        /// <summary>
        /// PHash对象
        /// </summary>
        PHash _phash;

        /// <summary>
        /// PHash算法比较图片相似度
        /// <br/>
        /// 返回相似度： 0-100
        /// </summary>
        /// <param name="image1"></param>
        /// <param name="image2"></param>
        /// <returns></returns>
        public static int PHashSimilarity(Bitmap image1, Bitmap image2)
        {
            if (image1 == null || image2 == null)
            {
                return 0;
            }

            try
            {
                // 将 Bitmap 转换为 Mat
                using (var mat1 = BitmapConverter.ToMat(image1))
                using (var mat2 = BitmapConverter.ToMat(image2))
                {
                    // 创建 PHash 对象
                    var phash = PHash.Create();

                    // 计算图像的哈希值
                    using (var hash1 = new Mat())
                    using (var hash2 = new Mat())
                    {
                        phash.Compute(mat1, hash1);
                        phash.Compute(mat2, hash2);

                        // 计算汉明距离
                        int distance = HammingDistance(hash1, hash2);

                        // 将汉明距离转换为相似度百分比
                        int maxDistance = hash1.Cols * 8; // 每个字节有8位
                        int similarity = (int)((1.0 - (double)distance / maxDistance) * 100);

                        return similarity;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error comparing images: {ex.Message}");
                return 0;
            }
        }

        /// <summary>
        /// PHash算法比较图片相似度
        /// <br />
        /// 返回相似度: 0-100
        /// </summary>
        /// <param name="image1"></param>
        /// <param name="image2"></param>
        /// <returns></returns>
        public int PHashSimilarity(Mat image1,Mat image2)
        {
            if(image1 == null || image2 == null || image1.Empty() || image2.Empty())
            {
                return 0;
            }

            try
            {
                if(_phash == null)
                {
                    _phash = PHash.Create();
                }
                var phash = _phash;

                // 计算图像的哈希值
                using (var hash1 = new Mat())
                using (var hash2 = new Mat())
                {
                    phash.Compute(image1, hash1);
                    phash.Compute(image2, hash2);

                    // 计算汉明距离
                    int distance = HammingDistance(hash1, hash2);

                    // 将汉明距离转换为相似度百分比
                    int maxDistance = hash1.Cols * 8; // 每个字节有8位
                    int similarity = (int)((1.0 - (double)distance / maxDistance) * 100);

                    return similarity;
                }

            }
            catch (Exception ex)
            {
                Item.logger.Log($"PHash相似度计算失败: {ex.Message}");
                throw new Exception($"PHash相似度计算失败: {ex.Message}",ex);
            }
        }

        /// <summary>
        /// 获取汉明距离
        /// </summary>
        /// <param name="hash1"></param>
        /// <param name="hash2"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static int HammingDistance(Mat hash1, Mat hash2)
        {
            if (hash1.Rows != hash2.Rows || hash1.Cols != hash2.Cols)
                throw new ArgumentException("Hash sizes do not match.");

            int distance = 0;
            for (int i = 0; i < hash1.Cols; i++)
            {
                byte b1 = hash1.Get<byte>(0, i);
                byte b2 = hash2.Get<byte>(0, i);
                distance += CountBits(b1 ^ b2);
            }
            return distance;
        }

        /// <summary>
        /// 计算整数中1的个数
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        private static int CountBits(int b)
        {
            int count = 0;
            while (b != 0)
            {
                count += b & 1;
                b >>= 1;
            }
            return count;
        }

        /// <summary>
        /// 判断 Bitmap 是否为纯色图像
        /// </summary>
        /// <param name="bitmap">输入的 Bitmap</param>
        /// <returns>如果是纯色则返回颜色字符串（#RRGGBB 或 #AARRGGBB），否则返回 null</returns>
        public static string GetSolidColor(Bitmap bitmap)
        {
            if (bitmap == null)
                return null;

            // 使用 LockBits 以提高性能
            var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);

            try
            {
                // 获取第一个像素的颜色作为参考
                Color firstColor;
                unsafe
                {
                    byte* firstPixel = (byte*)bitmapData.Scan0;
                    firstColor = GetPixelFromBytes(firstPixel, bitmap.PixelFormat);

                    // 检查所有像素是否与第一个像素相同
                    int bytesPerPixel = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8;
                    for (int y = 0; y < bitmapData.Height; y++)
                    {
                        byte* currentLine = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);

                        for (int x = 0; x < bitmapData.Width; x++)
                        {
                            byte* currentPixel = currentLine + (x * bytesPerPixel);
                            Color currentColor = GetPixelFromBytes(currentPixel, bitmap.PixelFormat);

                            if (!ColorsAreEqual(firstColor, currentColor))
                                return null;
                        }
                    }
                }

                // 如果是纯色，返回颜色字符串
                return firstColor.A == 255 ?
                    $"#{firstColor.R:X2}{firstColor.G:X2}{firstColor.B:X2}" :
                    $"#{firstColor.A:X2}{firstColor.R:X2}{firstColor.G:X2}{firstColor.B:X2}";
            }
            finally
            {
                bitmap.UnlockBits(bitmapData);
            }
        }

        /// <summary>
        /// 从字节指针获取 Color 对象
        /// </summary>
        private static unsafe Color GetPixelFromBytes(byte* pixelBytes, System.Drawing.Imaging.PixelFormat format)
        {
            switch (format)
            {
                case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                    return Color.FromArgb(pixelBytes[3], pixelBytes[2], pixelBytes[1], pixelBytes[0]);
                case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
                    return Color.FromArgb(pixelBytes[2], pixelBytes[1], pixelBytes[0]);
                default:
                    // 对于不支持的格式，回退到 GetPixel 方法
                    // 注意：这会影响性能，建议使用支持的像素格式
                    throw new NotSupportedException("Unsupported pixel format. Use Format32bppArgb or Format24bppRgb for better performance.");
            }
        }

        /// <summary>
        /// 比较两个颜色是否相同
        /// </summary>
        private static bool ColorsAreEqual(Color color1, Color color2)
        {
            return color1.A == color2.A &&
                   color1.R == color2.R &&
                   color1.G == color2.G &&
                   color1.B == color2.B;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public ImageDiffUtils()
        {
            _phash = PHash.Create();
        }


    }
}
